home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 0294.ZIP / SHELL2.ARC / CMDS.C < prev    next >
C/C++ Source or Header  |  1985-08-08  |  19KB  |  1,035 lines

  1. #include <dos.h>
  2. #include <stdio.h>
  3. #include <direct.h>
  4. #include <string.h>
  5. #include <process.h>
  6. #include <ctype.h>
  7. #include <time.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <signal.h>
  11. #include <setjmp.h>
  12.  
  13. #include "gen.h"
  14. #include "sh.h"
  15.  
  16.  
  17. /*
  18.  *    sh:  a Unix(tm) like command interpreter for MS-DOS.
  19.  *
  20.  *  by  Douglas Orr
  21.  *      Textset Inc.
  22.  *      Ann Arbor, Michigan
  23.  *
  24.  *  Copyright (c) 1985 Textset.   All rights reserved.
  25.  *
  26.  *  This program may be freely distributed, but not sold for profit.
  27.  *
  28.  */
  29.  
  30. /*   declare built-in functions  */
  31. Public b_ls(), b_echo(), b_pushd(), b_popd();
  32. Public b_pwd(), b_cd(), b_mkdir(), b_rmdir(), b_rm();
  33. Public b_history(), b_exit(), b_dirs(), b_rehash();
  34. Public b_set(), b_fgrep(), b_source();
  35.  
  36. Public int fcmp();
  37.  
  38. /*  disk transfer area  */
  39. typedef    union dta
  40.     {
  41.     struct {
  42.         char dt_dos[21];
  43. #define DosSub (0x10)
  44. #define    DosHid (0x02)
  45.         byte dt_attr;
  46.         short dt_time;
  47.         short dt_date;
  48.         unsigned short dt_size_low;
  49.         unsigned short dt_size_high;
  50.         char  dt_name[13];
  51.         } d;
  52.     short buf[128];
  53.     } Dta;
  54. Local Dta dta;
  55.  
  56. /*
  57.  *    give us an easily addressable disk transfer area 
  58.  */
  59. set_dta()
  60.     {
  61.  
  62.     union REGS regs;
  63.     union SREGS segregs;
  64.     Dta far * dta_addr = &dta;
  65.  
  66.     regs.h.ah = 0x1a;    /* set dta */
  67.     regs.x.dx = FP_OFF(dta_addr);
  68.     segregs.ds = FP_SEG(dta_addr);
  69.     intdosx( ®s, ®s, &segregs );
  70.  
  71.     }
  72.  
  73.  
  74. /*
  75.  *    set our disk transfer area and match the first file in the given
  76.  *  path.  
  77.  *  !! Warning:  uSoft routines that do disk accesses reset the
  78.  *  disk transfer area.  Don't call in between directory reads
  79.  *  examples: open, stat, etc.
  80.  *
  81.  *  ?! add flags to allow optionally getting hidden/volume file names
  82.  */
  83.  
  84. char *
  85. open_dir( ptr )
  86. char    * ptr;
  87.     {
  88.  
  89.     char far * fptr;
  90.     union REGS regs;
  91.     union SREGS segregs;
  92.  
  93.     set_dta();
  94.  
  95.     fptr = ptr;
  96.     regs.h.ah = 0x4e;    /* find first entry */
  97.     regs.x.dx = FP_OFF(fptr);
  98.     segregs.ds = FP_SEG(fptr);
  99.     regs.x.cx = DosSub;    /* look for normal files & subdirectories*/
  100.  
  101.     intdosx( ®s, ®s, &segregs );
  102.  
  103.     if( regs.x.cflag )
  104.         return( NULL );
  105.     else
  106.         /*  name of the current file in the dta  */
  107.         return( dta.d.dt_name );
  108.  
  109.     }
  110.  
  111. char *
  112. nxt_entry( ptr )
  113. char    * ptr;
  114.     {
  115.  
  116.     union REGS regs;
  117.  
  118.     regs.h.ah = 0x4f;    /* find next entry */
  119.     regs.x.cx = DosSub;    /* look for normal files & subdirs */
  120.  
  121.     intdos( ®s, ®s );
  122.  
  123.     if( regs.x.cflag )
  124.         return( NULL );
  125.     else
  126.         return( dta.d.dt_name );
  127.  
  128.     }
  129.  
  130.  
  131. /*        extract fields from dta        */
  132. dta_mode()
  133.     {
  134.  
  135.     char * ptr;
  136.     int    mode = 0;
  137.  
  138.     if( (ptr = strrchr( dta.d.dt_name, '.' )) )
  139.         {
  140.         if( (strcmpi( ptr, ".bat" ) == 0)
  141.         ||  (strcmpi( ptr, ".exe" ) == 0) 
  142.         ||  (strcmpi( ptr, ".com" ) == 0) )
  143.             mode |= S_IEXEC;
  144.         }
  145.  
  146.     if( dta.d.dt_attr & DosSub )
  147.         mode |= S_IFDIR;
  148.  
  149.     return( mode );
  150.  
  151.     }
  152.  
  153. /*
  154.  *    return most of the time info provided in struct tm
  155.  */
  156. struct tm *
  157. dta_time()
  158.     {
  159.  
  160.     Local struct tm dta_time;
  161.  
  162.     dta_time.tm_hour = (dta.d.dt_time >> 11) & 0x1f;
  163.     dta_time.tm_min = (dta.d.dt_time >> 5) & 0x3f;
  164.     dta_time.tm_sec = (dta.d.dt_time & 0x1f) * 2;
  165.     dta_time.tm_year = ((dta.d.dt_date >> 9) & 0x7f) + 80;
  166.     dta_time.tm_mon = ((dta.d.dt_date >> 5) & 0xf);
  167.     dta_time.tm_mday = (dta.d.dt_date & 0x1f);
  168.  
  169.     if( dta_time.tm_mon > 12 || dta_time.tm_mon < 1 )
  170.         dta_time.tm_mon = 0;
  171.  
  172.     return( &dta_time );
  173.  
  174.     }
  175.  
  176. long
  177. dta_size()
  178.     {
  179.     return( (((long)dta.d.dt_size_high) << 16) + dta.d.dt_size_low );
  180.     }
  181.  
  182.  
  183. /*    "disk" operations    */
  184.  
  185. /* 
  186.  *   change the current disk 
  187.  */
  188. chdsk( disk )
  189. int    disk;
  190.     {
  191.  
  192.     union REGS regs;
  193.  
  194.     if( isupper(disk) )
  195.         disk -= 'A';
  196.     else
  197.         disk -= 'a';
  198.  
  199.     if( disk < 0 || disk > 25 )
  200.         {
  201.         fprintf( stderr, "invalid drive\n" );
  202.         return( -1 );
  203.         }
  204.  
  205.     regs.h.ah = 0x0e;    /* change disk */
  206.     regs.h.dl = disk;    /* to this value */
  207.  
  208.     intdos( ®s, ®s );
  209.     return( 0 );
  210.  
  211.     }
  212.  
  213. bool
  214. isdev( disk )
  215. char * disk;
  216.     {
  217.     return( (strlen(disk) == 2) && (disk[1] == ':') );
  218.     }
  219.  
  220. getcdsk()
  221.     {
  222.  
  223.     union REGS regs;
  224.  
  225.     regs.h.ah = 0x19;    /* get current disk */
  226.     intdos( ®s, ®s );
  227.  
  228.     return( regs.h.al + 'a' );
  229.  
  230.     }
  231.  
  232.  
  233. #define    MaxCmdLen (15)
  234. #define Cm_Builtin (0x01)
  235. #define Cm_Batch (0x02)
  236.  
  237. typedef    struct cmds
  238.     {
  239.     char cm_name[MaxCmdLen];
  240.     char * cm_path;
  241.     short cm_flags;
  242.     int (* cm_rtne)();
  243.     } Cmds;
  244.  
  245. #define    MaxCmds (256)
  246. Local Cmds cmds[MaxCmds];
  247.  
  248.  
  249. /*   built-in commands  */
  250. Local struct bi {
  251.     char * bi_name;
  252.     int (* bi_rtne)();
  253.     } 
  254. builtins[] =
  255.     {
  256.     "ls", b_ls,
  257.     "echo", b_echo,
  258.     "cd", b_cd,
  259.     "pwd", b_pwd,
  260.     "pushd", b_pushd,
  261.     "pd", b_pushd,
  262.     "popd", b_popd,
  263.     "rm", b_rm,
  264.     "mkdir", b_mkdir,
  265.     "rmdir", b_rmdir,
  266.     "history", b_history,
  267.     "exit", b_exit,
  268.     "dirs", b_dirs,
  269.     "rehash", b_rehash,
  270.     "set", b_set,
  271.     "fgrep", b_fgrep,        /* msdos sucks */
  272.     "source", b_source,        /* just like on MTS */
  273.     NULL, NULL,
  274.     };
  275. Local int cmdcnt = 0;
  276.  
  277.  
  278.  
  279. /*    Command Parsing Stuff    */
  280.  
  281. add_cmd( cmd, path, flags, rtne )
  282. char * cmd;
  283. char * path;
  284. short flags;
  285. int (* rtne)();
  286.     {
  287.  
  288.     if( cmdcnt >= MaxCmds )
  289.         {
  290.         fprintf( stderr, "error: hash table overflow\n" );
  291.         return;
  292.         }
  293.  
  294.     /*    ?! make this into a real hash table, eventually  */
  295.     strcpy( cmds[cmdcnt].cm_name, cmd );
  296.     if( path )
  297.         cmds[cmdcnt].cm_path = strdup(path);
  298.     else
  299.         cmds[cmdcnt].cm_path = NULL;
  300.     cmds[cmdcnt].cm_flags = flags;
  301.     cmds[cmdcnt].cm_rtne = rtne;
  302.     cmdcnt++;
  303.  
  304.     }
  305.  
  306. /*
  307.  * ... ok ... so we're not really hashing anything
  308.  */
  309. rehash( path )
  310. char * path;
  311.     {
  312.  
  313.     char mypath[128];
  314.     char buf[128];
  315.     char cbuf[128];
  316.     Reg char * pptr;
  317.     char * ptr;
  318.     char * extptr;
  319.     char * cur_path;
  320.     int flags;
  321.     int i;
  322.  
  323.  
  324.     /*    ?! make this into a real hash table, eventually  */
  325.     for( i=0; i<cmdcnt; i++ )
  326.         {
  327.         if( cmds[i].cm_path )
  328.             free( cmds[i].cm_path );
  329.         }
  330.     cmdcnt = 0;
  331.  
  332.  
  333.     /*   add "built in" commands  */
  334.     for( i=0; builtins[i].bi_name; i++ )
  335.         add_cmd( builtins[i].bi_name, NULL, Cm_Builtin,
  336.             builtins[i].bi_rtne );
  337.  
  338.     /*  add the stuff in the path  */
  339.     for( pptr=path; *pptr; )
  340.         {
  341.  
  342.         if( *pptr == ';' )
  343.             ++pptr;
  344.  
  345.         cur_path = pptr++;
  346.         while( (*pptr != ';') && (*pptr != '\0') )
  347.             ++pptr;
  348.  
  349.         strncpy( mypath, cur_path, pptr-cur_path );
  350.         mypath[pptr-cur_path] = '\0';
  351.  
  352.         /*    open the directory    */
  353.         strcat( mypath, "\\*.*" );
  354.         ptr = open_dir( mypath );
  355.         mypath[ strlen(mypath)-4 ] = '\0';
  356.  
  357.         /*  find everything that looks executeable  */
  358.         for( ; ptr; ptr = nxt_entry() )
  359.             {
  360.  
  361.             strlwr( ptr );
  362.  
  363.             if( !(extptr = strrchr(ptr, '.'))
  364.             ||  (strcmp(extptr, ".exe") != 0  
  365.               && strcmp(extptr, ".bat") != 0
  366.               && strcmp(extptr, ".com") != 0) )
  367.                 continue;
  368.  
  369.             flags = 0;
  370.  
  371.             strncpy( cbuf, ptr, extptr-ptr );
  372.             cbuf[extptr-ptr] = '\0';
  373.             sprintf( buf, "%s\\%s", mypath, ptr );
  374.  
  375.             if( strcmp( extptr, ".bat" ) == 0 )
  376.                 flags |= Cm_Batch;
  377.  
  378.             add_cmd( cbuf, buf, flags, NULL );
  379.  
  380.             }
  381.  
  382.         }
  383.  
  384.     }
  385.  
  386.  
  387. #define MaxArgs (128)
  388. Local char * argv[MaxArgs];
  389.  
  390. /*
  391.  *    duplicate arg string, turning off all high bits
  392.  */
  393. char *
  394. astrdup(str)
  395. char * str;
  396.     {
  397.     Reg char * ptr;
  398.     char * val;
  399.  
  400.     val = ptr = strdup(str);
  401.     while( *ptr )
  402.         *ptr++ &= 0x7f;
  403.  
  404.     return( val );
  405.  
  406.     }
  407.  
  408. /*
  409.  *    dissect breaks the command into arguments
  410.  *
  411.  * !! ASSUME getbuf "escape"s all quotes within quotes, so quote
  412.  *    processing is trivial at this point
  413.  */
  414.  
  415. char * * 
  416. dissect( buf, bufsize )
  417. char * buf;
  418. int bufsize;
  419.     {
  420.  
  421.     int    done = False;
  422.     int argc = 0;
  423.     int i;
  424.     char * bufend;
  425.     char * wordend;
  426.  
  427.     /* ?! it might be better to store history as argv lists, and
  428.      *        do substitution after initial arg breakup
  429.      */
  430.  
  431.     i = strlen(buf);
  432.     if( i && buf[i-1] == '\n' )
  433.         buf[i-1] = '\0';
  434.  
  435.     if( !sub_hist( buf, bufsize ) )
  436.         return( NULL );
  437.  
  438.     /*  plant this stuff, for batch and mystery commands  */
  439.     argv[argc++] = "\\command";
  440.     argv[argc++] = "/c";
  441.  
  442.     bufend = buf+bufsize;
  443.  
  444.     while( !done )
  445.         {
  446.  
  447.         while( isspace(*buf) )
  448.             buf++;
  449.  
  450.         if( *buf ) {
  451.  
  452.         if( argc == MaxArgs )
  453.             {
  454.             fprintf(stderr, "error: too many arguments\n");
  455.             return( NULL );
  456.             }
  457.  
  458.  
  459.         if( *buf == '\'' || *buf == '"' )
  460.             {
  461.             /*  word starts on next character */
  462.             i = *buf++;
  463.             wordend = buf;
  464.             while( (*wordend != i) && *wordend )
  465.                 wordend++;
  466.             }
  467.         else
  468.             {
  469.             /*  normal space delimited word */
  470.             wordend = buf;
  471.             while( (!isspace(*wordend)) && *wordend )
  472.                 wordend++;
  473.             }
  474.  
  475.  
  476.         if( !*wordend )
  477.             done = True;
  478.  
  479.         /*  !! assuming at least one space between args */
  480.         *wordend = '\0';
  481.  
  482.         /*  can we do a wildcard substitution on this? */
  483.         if( iswild( buf ) )
  484.             {
  485.             if( (i = do_wildcard( buf, argv, argc )) == 0)
  486.                 {
  487.                 fprintf( stderr, "couldn't match %s\n",
  488.                     buf );
  489.                 return( NULL );
  490.                 }
  491.             else
  492.                 argc += i;
  493.             }
  494.         else
  495.             argv[argc++] = astrdup(buf);
  496.  
  497.         buf = wordend+1;
  498.  
  499.         }
  500.         else
  501.             done = True;
  502.  
  503.         }
  504.  
  505.     argv[argc] = NULL;
  506.  
  507.     /*  make with the I/O redirections  */
  508.     if( (argc = do_redirect( argc, argv )) < 0 )
  509.         {
  510.         fprintf( stderr, "redirection error\n" );
  511.         return( NULL );
  512.         }
  513.  
  514.     if( argc == 2 )
  515.         return( NULL );
  516.  
  517.     return( argv+2 );
  518.  
  519.     }
  520.  
  521.  
  522. /* ?!  Add []{} eventually  */
  523. iswild( buf )
  524. char * buf;
  525.     {
  526.  
  527.     while( *buf )
  528.         {
  529.         if( *buf++ == '*' )
  530.             return( True );
  531.         }
  532.  
  533.     return( False );
  534.     }
  535.  
  536.  
  537. /* ?!  Add []{} eventually  */
  538. do_wildcard( pat, argv, argc )
  539. char *  pat;
  540. char *  * argv;
  541. int argc;
  542.     {
  543.     char * * av;
  544.     char * ptr;
  545.     char * cwd;
  546.     char tmp[128];
  547.     char * endpat;
  548.     int tmpch;
  549.     int wargc;
  550.     int dev = -1;
  551.  
  552.     av = argv + argc;
  553.  
  554.     cwd = NULL;
  555.  
  556.     /*
  557.      * ?! currently only handle one level of wildcard  - FIXIT
  558.      *    UGLY ALERT
  559.      */
  560.     if( (ptr = strrchr( pat, '/' )) 
  561.      || (ptr = strrchr( pat, '\\' )) )
  562.         {
  563.  
  564.         /*
  565.          * save the directory spec, with which to rebuild file 
  566.          * names later 
  567.          */
  568.         strncpy( tmp, pat, ptr-pat+1 );
  569.         endpat = tmp + (ptr-pat) + 1;
  570.         tmpch = *ptr;
  571.         *ptr = '\0';
  572.  
  573.         if( pat[1] == ':' )
  574.             {
  575.             dev = getcdsk();
  576.             if( chdsk( pat[0] ) == -1 )
  577.                 goto bad_end;
  578.             pat += 2;
  579.             }
  580.  
  581.         /*  go to the directory you wish to examine  */
  582.         if( (cwd = getcwd( NULL, 128 )) == NULL )
  583.             goto bad_end;
  584.  
  585.         if( ptr != pat )
  586.             {
  587.             if( chdir( pat ) == -1 )
  588.                 {
  589.                 fprintf( "%s: no such directory\n", pat );
  590.                 goto bad_end;
  591.                 }
  592.             }
  593.         else
  594.             chdir( "/" );
  595.  
  596.         *ptr = tmpch;    /* back the way they were */
  597.         pat = ptr+1;
  598.  
  599.         }
  600.     else
  601.         endpat = tmp;
  602.  
  603.  
  604.     /*  save the pattern, and delete it from the buffer  */
  605.  
  606.     for( ptr=open_dir( "*.*" ); ptr; ptr = nxt_entry() )
  607.         {
  608.         strlwr(ptr);
  609.         if( ismatch( pat, ptr ) )
  610.             {
  611.             if( av-argv >= MaxArgs )
  612.                 {
  613.                 fprintf( stderr, "%d: too many arguments\n", 
  614.                     av-argv );
  615.                 goto bad_end;
  616.                 }
  617.             if( ptr[0] == '.' && pat[0] != '.' )
  618.                 continue;
  619.             strcpy( endpat, ptr );
  620.             *av++ = strdup(tmp);
  621.             }
  622.         }
  623.     *av = NULL;
  624.  
  625.     if( cwd )
  626.         {
  627.         chdir( cwd );
  628.         free( cwd );
  629.         }
  630.  
  631.     /*  sort the wildcarded arguments arguments  */
  632.     /*  !!  this can overflow your stack if you are unlucky  */
  633.     wargc = av - (argv+argc);
  634.     if( wargc > 1 )
  635.         qsort( (char *)(argv+argc), wargc, sizeof(char *), fcmp );
  636.  
  637.     if( dev != -1 )
  638.         chdsk(dev);
  639.     return( wargc );
  640.  
  641.     /*  he was a bad boy, and he came to a bad end */
  642. bad_end:
  643.     if( dev != -1 )
  644.         chdsk(dev);
  645.     return( 0 );
  646.  
  647.     }
  648.  
  649. /*    perform I/O redirections  */
  650. do_redirect( argc, argv )
  651. int argc;
  652. char * * argv;
  653.     {
  654.  
  655.     int i, j;
  656.     int skip;
  657.     char * file;
  658.     char * mode;
  659.     FILE * fd;
  660.     int direct;
  661.     int mod;
  662.  
  663.     /*
  664.      *  moderate UGLY ALERT
  665.      */
  666.     for( i=2; i<argc; )
  667.         {
  668.         if( ((direct = argv[i][0]) == '>') || (direct == '<') )
  669.             {
  670.             skip=1;
  671.             file = argv[i]+1;
  672.             mod = '\0';
  673.  
  674.             if( (*file == '>') || (*file == '&') )
  675.                 mod = *file++;
  676.  
  677.             /*  is file name in the second argument? */
  678.             if( *file == '\0' )
  679.                 {
  680.                 if( i == argc-1 )
  681.                     return( -1 );
  682.                 skip=2;
  683.                 file = argv[i+1];
  684.                 }
  685.  
  686.             if( direct == '<' )
  687.                 {
  688.                 mode = "r";
  689.                 fd = stdin;
  690.                 }
  691.             else
  692.                 {
  693.                 mode = "w";
  694.                 fd = stdout;
  695.                 if( mod == '>' )
  696.                     mode = "a";
  697.                 }
  698.  
  699.             if( freopen( file, mode, fd ) == NULL )
  700.                 return( -1 );
  701.  
  702.             /*  >& gets stderr & stdout  */
  703.             if( mod == '&' )
  704.                 dup2( 1, 2 );
  705.  
  706.             /*  UGLY part  */
  707.             for( j=i; j+skip <= argc ; j++ )
  708.                 argv[j] = argv[j+skip];
  709.             argc -= skip;
  710.  
  711.             }
  712.         else
  713.             i++;
  714.         }
  715.  
  716.     return( argc );
  717.  
  718.     }
  719.  
  720.  
  721. /*
  722.  *    perform history substitutions
  723.  */
  724.  
  725. /*  ?!  add  :modifiers, and ^^^ substitutions  */
  726. #define HistMax (50)
  727. short    hindex[HistMax];
  728. char    * history[HistMax] = { NULL, };
  729. short    hind = 0;
  730. short    hmax = HistMax;
  731. short    hcount = 0;
  732.  
  733. sub_hist( buf, bufsize )
  734. char * buf;
  735. int bufsize;
  736.     {
  737.  
  738.     char * hptr;
  739.     char * hend;
  740.     char * sub = NULL;
  741.     int ind;
  742.     int hval;
  743.     char tmpchr;
  744.     int i;
  745.     char * to, * from;
  746.     int sublen;
  747.     int cmdlen;
  748.  
  749.     for( hptr=buf; (hptr = strchr( hptr, '!' )); )
  750.         {
  751.  
  752.         sub = NULL;
  753.         ind = hind-1;
  754.         if( ind < 0 )
  755.             ind = hmax-1;
  756.  
  757.         if( *(hptr+1) == '!' )
  758.             hend = hptr+2;
  759.         else
  760.             {
  761.             for( hend=hptr+1; 
  762.                  *hend && !(isspace(*hend) || ispunct(*hend)); 
  763.                  hend++)
  764.                 /* find end of history spec */;
  765.             }
  766.  
  767.         /*   case !!  */
  768.         if( *(hptr+1) == '!' )
  769.             {
  770.             /* !! -> insert previous command  */
  771.             if( (sub = history[ind]) == NULL )
  772.                 goto noevent;
  773.             }
  774.         else
  775.         /*   case !num  */
  776.         if( isdigit(*(hptr+1)) )
  777.             {
  778.             /* !## -> insert command ## */
  779.             tmpchr = *hend;
  780.             *hend = '\0';
  781.             hval = atoi( hptr+1 );
  782.             *hend = tmpchr;
  783.  
  784.             for( i=0; i<hmax; i++ )
  785.                 {
  786.                 if( ind < 0 )
  787.                     ind = hmax-1;
  788.  
  789.                 if( history[ind] == NULL ) break;
  790.  
  791.                 if( hindex[ind] == hval )
  792.                     {
  793.                     sub = history[ind];
  794.                     break;
  795.                     }
  796.                 ind--;
  797.                 }
  798.             }
  799.         else
  800.         /* !str -> insert history string starting with "str" */
  801.             {
  802.             for( i=0; i<hmax; i++ )
  803.                 {
  804.                 if( ind < 0 )
  805.                     ind = hmax-1;
  806.  
  807.                 if( history[ind] == NULL ) break;
  808.  
  809.                 if( strncmp( hptr+1, history[ind], (hend-hptr)-1 ) == 0 )
  810.                     {
  811.                     sub = history[ind];
  812.                     break;
  813.                     }
  814.                 ind--;
  815.                 }
  816.             }
  817.  
  818.         if( sub == NULL )
  819.             {
  820.             noevent:
  821.                 fprintf(stderr,"%.*s: event not found\n", 
  822.                     hend-hptr-1, hptr+1);
  823.                 return( False );
  824.             }
  825.         else
  826.             {
  827.  
  828.             /*  perform substitution  */
  829.             sublen = strlen(sub);
  830.             cmdlen = strlen(buf);
  831.             if( (cmdlen - (hend-hptr) + sublen) > bufsize )
  832.                 {
  833.                 fprintf( stderr, "event too large\n" );
  834.                 return( False );
  835.                 }
  836.  
  837.             /*  make a null terminated string out of this  */
  838.             tmpchr = *hend;
  839.             *hend = '\0';
  840.  
  841.             if( cmdlen - (hend-hptr) + sublen > bufsize )
  842.                 {
  843.                 fprintf( stderr, "substitution too large\n" );
  844.                 return( False );
  845.                 }
  846.  
  847.             /*    do the substitution  */
  848.             insert(hptr,hend-hptr,(buf+cmdlen)-hptr,sub,sublen);
  849.  
  850.             /*  replace the original character  */
  851.             *(hptr+sublen) = tmpchr;
  852.  
  853.             }
  854.  
  855.         }
  856.  
  857.  
  858.     /*  retire old buffer if we have wrapped around  */
  859.     if( history[hind] )
  860.         free( history[hind] );
  861.  
  862.     /*  record this buffer for future histories */
  863.     hindex[hind] = ++hcount;
  864.     history[hind++] = astrdup( buf );
  865.     if( hind >= hmax )
  866.         hind = 0;
  867.  
  868.     /*  echo substituted string */
  869.     if( sub )
  870.         fprintf( stderr, "%s\n", buf );
  871.  
  872.     return( True );
  873.  
  874.     }
  875.  
  876. /*   UGLY ALERT  */
  877. insert( old, oldlen, totlen, new, newlen )
  878. char * old;    /*  history string  */
  879. int oldlen;    /*  size of history string */
  880. int totlen;    /*  length from start of history to end of command */
  881. char * new;    /*  replacement string  */
  882. int newlen;    /*  size of replacement string */
  883.     {
  884.  
  885.     Reg char * from, * to;
  886.     int i;
  887.  
  888.     /*  do the substitution  */
  889.  
  890.     if( newlen < oldlen )
  891.         {
  892.         /*  shift left  */
  893.         to = old+newlen;
  894.         from = old+oldlen;
  895.         while( (*to++ = *from++) )
  896.             /* shift, shift, shift, shift */;
  897.         }
  898.     else
  899.     if( newlen > oldlen )
  900.         {
  901.         /*  shift right  */
  902.         from = old+totlen;  /* start with trailing null */
  903.         to = from + (newlen - oldlen);
  904.         for( i = (newlen-oldlen); i-- >= 0; )
  905.             *to-- = *from--;
  906.         }
  907.  
  908.     /*  stick in the new command  */
  909.     from = new;
  910.     to = old;
  911.     for( i=0; i<newlen; i++ )
  912.         *to++ = *from++;
  913.  
  914.     }
  915.  
  916.  
  917. jmp_buf sbuf;
  918. sig_handle()
  919.     {
  920.     /*  reset the interrupt signal */
  921.     signal( SIGINT, SIG_IGN );
  922.     /*  bounce back  */
  923.     longjmp( sbuf, True );
  924.     }
  925.  
  926. /*   locate the appropriate executable command and doit */
  927. cmd( argv, envp )
  928. char    * * argv;
  929. char    * * envp;
  930.     {
  931.  
  932.     Reg int len;
  933.     Reg int i;
  934.     char * cmdptr;
  935.     char * ptr;
  936.     int rc;
  937.     int batch;
  938.     struct stat statb;
  939.  
  940.     cmdptr = NULL;
  941.     batch = False;
  942.  
  943.     /*   is this a specific path reference  */
  944.     if( strchr( argv[0], '/' )  == NULL 
  945.     &&  strchr( argv[0], '\\' ) == NULL )
  946.         {
  947.  
  948.         len = strlen( argv[0] );
  949.  
  950.         /*  is this really a drive selection? */
  951.         if( (len == 2) && (argv[0][1] == ':') )
  952.             return( chdsk( argv[0][0] ) );
  953.  
  954.         /*
  955.          * check . first  ... UGLY ALERT  (a real hashing scheme
  956.          * could take care of this a little more nicely)
  957.          */
  958.         if( stat( argv[0], &statb ) == -1
  959.         ||  (statb.st_mode & S_IEXEC) == 0 )
  960.         {
  961.  
  962.         /*  not in .  is it in the "hash" table?  */
  963.         for( i=0; i<cmdcnt; i++ )
  964.             {
  965.             if( len == strlen( cmds[i].cm_name )
  966.             &&  (strncmp( cmds[i].cm_name, argv[0], len ) == 0 ))
  967.                 break;
  968.             }
  969.  
  970.         if( i < cmdcnt )
  971.             {
  972.             cmdptr = cmds[i].cm_path;
  973.  
  974.             /*   a built in command? */
  975.             if( cmds[i].cm_flags & Cm_Builtin )
  976.                 {
  977.  
  978.                 if( setjmp(sbuf) )
  979.                     {
  980.                     fprintf( stderr, "SH: interrupt\n" );
  981.                     return( -1 );
  982.                     }
  983.                 signal( SIGINT, sig_handle );
  984.  
  985.                 rc = (*cmds[i].cm_rtne)(argv,envp);
  986.  
  987.                 signal( SIGINT, SIG_IGN );
  988.                 return( rc );
  989.                 }
  990.             else
  991.                 batch = (cmds[i].cm_flags & Cm_Batch);
  992.  
  993.             }
  994.         }
  995.  
  996.         }
  997.     else
  998.         {
  999.  
  1000.         /*  some sort of a specific path invocation  */
  1001.         cmdptr = argv[0];
  1002.  
  1003.         /*  reality check */
  1004.         if( (ptr = strrchr( cmdptr, '.' )) )
  1005.             {
  1006.             if( strcmp( ptr, ".bat" ) == 0 )
  1007.                 batch = True;
  1008.             }
  1009.  
  1010.         }
  1011.  
  1012.     if( cmdptr && !batch )
  1013.         {
  1014.         /*  invoke the specific command  */
  1015.         if( (rc = spawnve( P_WAIT, cmdptr, argv, envp )) < 0)
  1016.             perror( argv[0] );
  1017.         return( rc );
  1018.         }
  1019.     else
  1020.         {
  1021.         /* 
  1022.          * let DOS take a crack at it - this is not in the true Unix
  1023.          * tradition, but pragmatically, it works out well for
  1024.          * stuff like "mode," etc.
  1025.          * 
  1026.          * !! IMPORTANT - argv always has arguments "\command" "/c" 
  1027.          *    as argv[-2,-1]
  1028.          */
  1029.         if( (rc = spawnve( P_WAIT, "\command", argv-2, envp )) < 0)
  1030.             perror( argv[0] );
  1031.         return( rc );
  1032.         }
  1033.  
  1034.     }
  1035.